/***************************************************************************
 *   Copyright (C) 2009 by Bernhard Neuhofer   *
 *   mail@bneu.at   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#ifndef ROLLBACKABLELP_H
#define ROLLBACKABLELP_H


#include "AbstractLp.h"
#include "inQueue.h"
#include "vectorOutQueue.h"
#include "vectorInQueue.h"
#include "memento.h"
#include "../tools/log.h"


#include <vector>
#include <deque>
#include <map>

/**
* Implements logic for rollbackable Lps (TW,SQTW)
*/
class RollbackableLp:public AbstractLp
{
private:
	/** Vector with 1 to n InQueues */
	vector<InQueue*> _inQueues;
	/** OutQueue */
	VectorOutQueue* _outQueue;

	

	
	
	
	/**
	* A state is used to save all internas of a rollbackable LP for rollbacks
	*/
	class State
	{
	private:
		/** LVT of the state */
		double _lvt;
		
		/** Hash with queue# and a reference to each InputQueues last read message */
		map<unsigned int, Message*> _lastReads;
		/** OutputQueue */
		VectorOutQueue* _storedOutQueue;
		
		/** Associated mement*/
		Memento* _memento;
	public:
		/**
		 *               Constructs a state
		 * @param lvt The LVT
		 * @param inQueues Vector with Inqueues
		 * @param outQueue The OutQueue
		 * @param memento The associated memento
		 */
		State(double lvt, vector<InQueue*> inQueues, VectorOutQueue* outQueue,Memento* memento);
		/**
		 *               Returns the vector with the last read messages of each InputQueue
		 * @return map
		 */
		map<unsigned int, Message*> getLastReads();
		/**
		 *               Returns the LVT of the saved state
		 * @return lvt of the saved state
		 */
		double getLvt();
		/**
		 *               Returns the OutQueue
		 * @return VectorOutQueue The outQueue
		 */
		VectorOutQueue* getOutQueue();
		/**
		 *               Returns the saved memento
		 * @return The saved Memento
		 */
		Memento* getMemento();

	};
	
	/**StateStack */
	deque<State*> _stateStack;
	/**Flag LP idle if no messages are waiting to be processed */
	bool _terminated;

public:

	/**
	 *        Constructor for Tollbackable Lp.
	 * @param id 
	 */
	RollbackableLp(int id):AbstractLp(id),_terminated(false)
	{
	_inQueues.push_back(new VectorInQueue());
	FILE_LOG(logDEBUG)<<"Creating RollbackableLp";
	}

	/**
	 *        @see AbstractLp#doStep
	 */
	void doStep();
	/**
	 *        Puts the LPs messages from the InBuffer to the qppropriate Inqueues.
	*	If the LP ownes a SQTW adapter, the decision is delegated to the adapter.
	*	In all other cases all messages are put into the same Inqueue.
	*	If a straggler message is received a rollback to the last consistand state is performed
	 */
	void processInBuffer();
	/**
	 *        @see AbstectLp#sendMessage
	 * @param message 
	 */
	void sendMessage(Message* message);
	/**
	 *        @see AbstractLp#getLvt
	 * @return 
	 */
	double getLvt();

	/**
	 *        Tidy up the state stack and prune the Inqueues
	 */
	void fossilCollect();
	


};


#endif